﻿using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Data;
using System.IO;
using System.Text;

/// <summary>
/// A4纸张，左下角为(0,0)
/// 行距(Leading)
/// </summary>

namespace ITextSharpPDF
{
    public class PDFGenerator
    {
        //中文字体-宋体
        private static string fontCHN = (AppDomain.CurrentDomain.BaseDirectory + "Font\\simsun.ttc,0").Replace("\\", "/");
        private static BaseFont simsunFont = BaseFont.CreateFont(fontCHN, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

        //宋体标题
        private static Font font = null;

        private int fontSize = 20;
        /// <summary>
        /// 字体大小
        /// </summary>
        public int FontSize
        {
            get { return fontSize; }
            set
            {
                font = new Font(simsunFont, value);
                fontSize = value;
            }
        }

        private int imageScaleAbsolute = 100;
        public int ImageScaleAbsolute
        {
            get { return imageScaleAbsolute; }
            set
            {
                imageScaleAbsolute = value;
            }
        }

        private Document doc = null;
        private PdfWriter pdfWriter = null;
        private FileStream fs = null;

        public PDFGenerator(string filePath)
        {
            //顺序不要改变
            //生成Document实例、创建文件流、创建页眉页脚、写入元数据、打开文档、写入内容、关闭文档、关闭文件流、设置水印
            try
            {
                //A4纸尺寸：595*420，单位：磅
                doc = new Document(PageSize.A4);//默认边距，36磅
                font = new Font(simsunFont, FontSize);
                ImageScaleAbsolute = (int)(doc.Right - doc.RightMargin);
                fs = new FileStream(filePath, FileMode.Create);
                pdfWriter = PdfWriter.GetInstance(doc, fs);
                pdfWriter.CloseStream = false;//把doc内容写入流中

            }
            catch (DocumentException ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 获取当前文档
        /// </summary>
        public Document CurrentDocument { get { return doc; } }

        /// <summary>
        /// 设置水印
        /// </summary>
        /// <param name="pdfFilePath"></param>
        public void SetWaterMark(string pdfFilePath, string imageFilePath, float waterMarkSize)
        {
            PdfReader reader = null;
            PdfStamper stamper = null;
            string newPDFFileName = "";

            try
            {
                reader = new PdfReader(pdfFilePath);

                string waterPDF = Path.GetDirectoryName(pdfFilePath);
                string fileWater = Path.GetFileName(pdfFilePath).Replace(".pdf", "") + "-Stamper.pdf";

                newPDFFileName = Path.Combine(waterPDF, fileWater);

                stamper = new PdfStamper(reader, new FileStream(newPDFFileName, FileMode.OpenOrCreate));

                Image img = Image.GetInstance(imageFilePath);

                float width = doc.PageSize.Width;
                float height = doc.PageSize.Height;

                //像素
                float percent = waterMarkSize / img.Width;
                img.ScaleAbsoluteWidth(waterMarkSize);//缩放图片指定宽度
                img.ScaleAbsoluteHeight(img.Height * percent);//等比例缩放高度
                img.SetAbsolutePosition((width - waterMarkSize) / 2, (height - img.Height * percent) / 2);//设置水印位置
                img.Rotation = 95;//旋转角度

                //指定颜色透明,如：白色
                img.Transparency = new int[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

                //设置透明度
                //create new graphics state and assign opacity
                PdfGState graphicsState = new PdfGState();
                graphicsState.FillOpacity = 0.2F; // (or whatever)
                                                  //set graphics state to pdfcontentbyte
                PdfContentByte contentByte;
                int j = 0;
                int n = reader.NumberOfPages;
                while (j < n)
                {
                    j++;
                    contentByte = stamper.GetOverContent(j);
                    contentByte.SetGState(graphicsState);//设置透明度
                    contentByte.AddImage(img);
                }
            }
            finally
            {
                if (stamper != null) stamper.Close();
                if (stamper != null) reader.Close();

                //改名
                if (File.Exists(newPDFFileName))
                {
                    File.Delete(pdfFilePath);
                    FileInfo fi = new FileInfo(newPDFFileName);
                    fi.MoveTo(pdfFilePath);
                }
            }
        }

        /// <summary>
        /// 添加页眉、页脚
        /// </summary>
        /// <param name="imgPath">Logo图片路径</param>
        /// <param name="content">页眉文字内容</param>
        /// <param name="logoSize">Logo大小</param>
        /// <param name="numbered">页脚是否显示页数</param>
        /// <param name="numbered">页脚文字内容</param>
        public void SetPageHeader(string imgPath, string headerContent, string footerContent, int logoSize, bool numbered)
        {
            // we Add a Header that will show up on PAGE 1
            Phrase phrase = new Phrase();
            Image image = Image.GetInstance(imgPath);

            //TODO:这里的高度要自适应不同电脑的 DPI
            image.ScaleAbsoluteWidth(logoSize);//等比例缩放指定宽度
            image.ScaleAbsoluteHeight(logoSize);//等比例缩放指定高度
            Chunk chunk = new Chunk(image, 0, -5);

            Chunk contentChunk = new Chunk(headerContent, font);

            phrase.Add(chunk);
            phrase.Add(contentChunk);
            HeaderFooter header = new HeaderFooter(phrase, false);


            doc.Header = header;
            HeaderFooter footer = new HeaderFooter(new Phrase(footerContent), numbered);
            footer.Alignment = 1;
            footer.BorderWidthTop = 0;
            doc.Footer = footer;
        }

        /// <summary>
        /// 在PDF页面固定位置输出文本
        /// PDF中左下角为(0,0)，默认有页边距36
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="text">写入的文本</param>
        /// <param name="font">字体</param>
        /// <param name="urx">X</param>
        /// <param name="ury">Y</param>
        /// <param name="llx">width</param>
        /// <param name="lly">height</param>
        public void SetText(PdfWriter writer, string text, Font font, float urx, float ury, float llx, float lly)
        {
            //在固定位置显示文本
            ColumnText ct = new ColumnText(writer.DirectContent);
            ct.SetSimpleColumn(llx, lly, urx, ury);
            ct.AddElement(new Paragraph(text, font));
            ct.Go();
        }

        /// <summary>
        /// 在PDF生成表格
        /// </summary>
        public void SetTable(DataTable dt, int headerFontSize = 24, int contentFontSize = 20, float[] columnWidth = null)
        {
            iTextSharp.text.pdf.PdfPTable datatable = new PdfPTable(dt.Columns.Count);
            if (columnWidth != null)
            {
                datatable.SetWidths(columnWidth);
            }
            datatable.WidthPercentage = 100;
            datatable.HeaderRows = 1;

            int tempFontsize = FontSize;
            FontSize = headerFontSize;
            for (int i = 0; i <= dt.Columns.Count - 1; i++)
            {
                Phrase ph = new Phrase(dt.Columns[i].ColumnName, font);
                iTextSharp.text.pdf.PdfPCell cell1 = new PdfPCell(ph);
                cell1.HorizontalAlignment = Element.ALIGN_CENTER;
                cell1.BackgroundColor = new iTextSharp.text.Color(0xC0, 0xC0, 0xC0);
                datatable.AddCell(cell1);
            }

            FontSize = contentFontSize;
            foreach (DataRow row in dt.Rows)
            {
                for (int i = 0; i < row.ItemArray.Length; i++)
                {
                    datatable.AddCell(new Phrase(row[i].ToString(), font));
                }
            }

            FontSize = tempFontsize;

            doc.Add(datatable);
        }

        /// <summary>
        /// 添加PDF元数据
        /// </summary>
        /// <param name="title">标题</param>
        /// <param name="author">作者</param>
        /// <param name="creator">创作者</param>
        /// <param name="subject">学科</param>
        /// <param name="keywords">关键字</param>
        public void SetMateData(string title = null, string author = null, string creator = null, string subject = null, string keywords = null)
        {
            doc.AddSubject(subject);
            doc.AddKeywords(keywords);
            doc.AddCreator(creator);
            doc.AddAuthor(author);
            doc.AddTitle(title);
        }

        /// <summary>
        /// 加密pdf内容
        /// </summary>
        /// <param name="pdfWriter">pdf记录器</param>
        /// <param name="userPass">用户密码</param>
        /// <param name="ownerPass">所有者密码</param>
        public void SetEncryption(string userPass, string ownerPass)
        {
            pdfWriter.SetEncryption(PdfWriter.STRENGTH128BITS, userPass, ownerPass, PdfWriter.AllowCopy | PdfWriter.AllowPrinting);
        }

        /// <summary>
        /// 添加段落
        /// </summary>
        /// <param name="font">段落字体</param>
        /// <param name="content">内容</param>
        public void SetContent(params string[] content)
        {
            //设置段落
            // 等级关系： Chunk < Phrase < Paragraph
            //段落里面可以添加很多块(Chunk)和组(Phrase),添加的块和组需要主动添加换行符才会换行，每个组和块可以单独设置字体
            //Paragraph包含换行符
            foreach (var item in content)
            {
                doc.Add(new Paragraph(item, font));
            }
        }

        public void SetContent(int fontsize, params string[] content)
        {
            //设置段落
            // 等级关系： Chunk < Phrase < Paragraph
            //段落里面可以添加很多块(Chunk)和组(Phrase),添加的块和组需要主动添加换行符才会换行，每个组和块可以单独设置字体
            //Paragraph包含换行符
            int temp = this.FontSize;
            FontSize = fontsize;
            foreach (var item in content)
            {
                doc.Add(new Paragraph(item, font));
            }

            FontSize = temp;
        }

        /// <summary>
        /// 设置图片
        /// </summary>
        /// <param name="image">System.Drawing.Image，图片实例</param>
        /// <param name="format">System.Drawing.Imaging.ImageFormat,图片格式</param>
        public void SetImage(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat format)
        {
            Image img = Image.GetInstance(image, format);
            AddImage(img);
        }

        public void SetImage(System.Drawing.Image image, Color color)
        {
            Image img = Image.GetInstance(image, color);
            AddImage(img);
        }

        public void SetImage(Image image)
        {
            Image img = Image.GetInstance(image);
            AddImage(img);
        }

        public void SetImage(string filename)
        {
            Image img = Image.GetInstance(filename);

            AddImage(img);
        }

        public void SetImage(string fileName, int imageScaleAbsolute)
        {
            Image img = Image.GetInstance(fileName);
            float percent = imageScaleAbsolute / img.Width;
            img.ScaleAbsoluteWidth(imageScaleAbsolute);//缩放图片指定宽度
            img.ScaleAbsoluteHeight(img.Height * percent);//等比例缩放高度

            doc.Add(img);
        }

        private void AddImage(Image image)
        {
            //像素
            float percent = ImageScaleAbsolute / image.Width;
            image.ScaleAbsoluteWidth(ImageScaleAbsolute);//缩放图片指定宽度
            image.ScaleAbsoluteHeight(image.Height * percent);//等比例缩放高度

            doc.Add(image);
        }

        public void Open()
        {
            doc.Open();
        }

        public void Close()
        {
            doc.Close();

            //保存PDF文件
            MemoryStream ms = new MemoryStream();
            if (fs != null)
            {
                byte[] bytes = new byte[fs.Length];//定义一个长度为fs长度的字节数组
                fs.Read(bytes, 0, (int)fs.Length);//把fs的内容读到字节数组中
                ms.Write(bytes, 0, bytes.Length);//把字节内容读到流中
                fs.Flush();
                fs.Close();
            }
        }

        ~PDFGenerator()
        {
            if (doc.IsOpen())
            {
                doc.Close();
            }
        }
    }
}
